/**
 * 一个数据类型检查工具
 *
 * 使用 “createDescription” 创建一个类型描述配置对象
 * 使用 “checkValueByDescription” 来对目标值进行检查
 *
 *
 * @author  韦胜健
 * @date    2025/5/26 18:11
 */

/*---------------------------------------definition start-------------------------------------------*/

type iConstructor<T> = { new(): T }
type iDescriptionWithDefault<T> = { type: iConstructor<T>, default: () => T }
type iDescriptionWithoutDefault<T> = { type: iConstructor<T> }

type iObjectValueType<T, K extends keyof T = keyof T> = T extends iConstructor<infer TT> ? TT : {
  [k in K]: T[k] extends iConstructor<infer R1> ? (R1 | undefined) : (
    T[k] extends iDescriptionWithDefault<infer R2> ?
      R2 : T[k] extends iDescriptionWithoutDefault<infer R2> ? (R2 | undefined) : unknown
    )
};

type iObjectDescription = { [k: string]: iConstructor<any> | iDescriptionWithoutDefault<any> | iDescriptionWithDefault<any> }

export function createDescription<Description extends iObjectDescription | iConstructor<any>>(description: Description) {return description;}

export function createArrayFieldDescription<Description extends iObjectDescription | iConstructor<any>>(description: Description): iDescriptionWithoutDefault<iObjectValueType<Description>[]>
export function createArrayFieldDescription<Description extends iObjectDescription | iConstructor<any>>(description: Description, _default: () => Partial<iObjectValueType<Description>>[]): iDescriptionWithDefault<iObjectValueType<Description>[]>
export function createArrayFieldDescription<Description extends iObjectDescription | iConstructor<any>>(description: Description, _default?: () => any) {
  if (!!_default) {
    return { type: description, default: _default };
  } else {
    return { type: description };
  }
}

export function createObjectFieldDescription<Description extends iObjectDescription>(description: Description): iDescriptionWithoutDefault<iObjectValueType<Description>>
export function createObjectFieldDescription<Description extends iObjectDescription>(description: Description, _default: () => Partial<iObjectValueType<Description>>): iDescriptionWithDefault<iObjectValueType<Description>>
export function createObjectFieldDescription<Description extends iObjectDescription>(description: Description, _default?: () => any) {
  if (!!_default) {
    return { type: description, default: _default };
  } else {
    return { type: description };
  }
}

function checkValueByFieldDescription<Value>(checkValue: Value, fieldDescription: iConstructor<any> | iDescriptionWithoutDefault<any> | iDescriptionWithDefault<any>): Value {
  if (checkValue == null) {
    /*没有值，尝试获取默认值*/
    if ('default' in fieldDescription) {checkValue = fieldDescription.default();}
  }
  /*没有默认值*/
  if (checkValue == null) {return checkValue;}

  /*只有当 fieldDescription.type 为object的时候，才去递归检查checkValue的每一个属性值*/
  if (!('type' in fieldDescription && typeof fieldDescription.type === "object")) {return checkValue;}

  if (Array.isArray(checkValue)) {
    for (let i = 0; i < checkValue.length; i++) {
      checkValue[i] = checkValueByDescription(checkValue[i], fieldDescription.type);
    }
  } else if (typeof checkValue === "object") {
    checkValue = checkValueByDescription(checkValue, fieldDescription.type);
  }

  return checkValue;
}

export function checkValueByDescription(checkValue: any, objectDescription: iObjectDescription) {
  if (checkValue == null) {checkValue = {};}
  if (Array.isArray(checkValue)) {
    return checkValue.map((checkValueItem): any => checkValueByDescription(checkValueItem, objectDescription));
  } else if (typeof checkValue === "object") {
    Object.entries(objectDescription).forEach(([key, fieldDescription]) => {
      checkValue[key] = checkValueByFieldDescription(checkValue[key], fieldDescription);
    });
  }
  return checkValue;
}

/*---------------------------------------definition end-------------------------------------------*/

/*---------------------------------------test start-------------------------------------------*/

// /*创建类型描述*/
// const objectDescription = createDescription({
//   id: String,
//   name: String,
//   age: Number,
//   gender: Boolean,
//   age2: { type: Number },
//   age3: { type: Number, default: () => 10 },
//
//   content1: createArrayFieldDescription(String),
//   content2: createArrayFieldDescription(String, () => []),
//   children: createArrayFieldDescription({
//     code: { type: String },
//     weight: { type: Number, default: () => 10 }
//   }),
//
//   subValue: createObjectFieldDescription({
//     subId: String,
//     subAge: Number,
//     subAge2: { type: Number },
//     subAge3: { type: Number, default: () => 11 },
//     subChildren: createArrayFieldDescription(String, () => [/*1, */"1"]),
//   }, () => ({ subId: undefined, subAge: undefined, subAge2: undefined, subAge3: 1, subChildren: [/*1, */"1"] }))
// });
//
// const val = createValueByDescription(objectDescription);
//
// /*普通字符串字段*/
// val.id.trim();
// /*普通数字字段，直接用Number构造函数配置*/
// val.age.toFixed(2);
// /*普通数字字段，用{type:Number}配置*/
// val.age2.toFixed(2);
// /*普通数字字段，带默认值*/
// val.age3.toFixed(2);
// /*普通对象数组字段*/
// val.children?.forEach(item => [item.weight.toFixed(0), item.code.trim()]);
// /*普通字符串数组字段*/
// val.content1.forEach((item) => {item.trim();});
// /*普通字符串数组字段，带默认值*/
// val.content2.forEach((item) => {item.trim();});
//
// /*子对象 字符串字段*/
// val.subValue.subId.trim();
// /*子对象数字字段，用构造函数配置*/
// val.subValue.subAge.toFixed(2);
// /*子对象数字字段，用{type:Number}配置*/
// val.subValue.subAge2.toFixed(2);
// /*子对象数字字段，用{type:Number}配置，带默认值*/
// val.subValue.subAge3.toFixed(2);
// /*子对象字符串数组字段*/
// val.subValue.subChildren.forEach(item => {item.trim();});

/*---------------------------------------test end-------------------------------------------*/

/*---------------------------------------resume start-------------------------------------------*/

// const TestResumeDescription = createDescription({
//   title: { type: String, default: () => '简历标题' },
//   primary: { type: String, default: () => '#4e7282' },
//   secondary: { type: String, default: () => '#c19f67' },
//   avatar: { type: String, default: () => 'http://110.42.233.30/web/upload_file/20250519164713_0196e7b9-c2be-71ad-94a9-42fbea3d336c/work_avatar.png' },
//   basicInfo: createObjectFieldDescription({
//     title: { type: String, default: () => '基本信息' },
//     data: createArrayFieldDescription({
//       label: String,
//       type: String,
//       val: String,
//       icon: String,
//     })
//   }),
//   education: createObjectFieldDescription({
//     title: { type: String, default: () => '教育经历' },
//     data: createArrayFieldDescription({
//       time: String,
//       school: String,
//       program: String,
//       content: createArrayFieldDescription(String),
//     })
//   }),
//   experience: createObjectFieldDescription({
//     title: { type: String, default: () => '工作经历' },
//     data: createArrayFieldDescription({
//       time: String,
//       company: String,
//       role: String,
//       content: createArrayFieldDescription(String, () => ['111', '222']),
//     }, () => [
//       { time: '111', company: '111', role: '111' },
//       { time: 'aaa', company: 'aaa', role: 'aaa', content: ['aaa'] },
//     ])
//   }, () => ({})),
//   externals: createArrayFieldDescription({
//     title: String,
//     content: createArrayFieldDescription(String)
//   })
// });

// const resume = checkValueByDescription({}, TestResumeDescription);
//
// console.log(ResumeDescription, resume);

// resume.title.trim();
// resume.primary.trim();
// resume.secondary.trim();
// resume.basicInfo.title.trim();
// resume.basicInfo.data.forEach(item => {item.label.trim();});

/*---------------------------------------resume end-------------------------------------------*/
